package org.wltea.analyzer.dic;

import cn.hutool.core.collection.CollUtil;
import com.choudou5.solr.util.LogDeBugUtil;
import com.choudou5.solr.util.bean.WordBean;
import com.choudou5.solr.util.jdbc.DBUtil;
import com.choudou5.solr.util.thread.TimerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wltea.analyzer.cfg.Configuration;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.SQLException;
import java.util.*;

public class Dictionary {

  private static final Logger logger = LoggerFactory.getLogger(Dictionary.class);

  private static Dictionary singleton;
  private DictSegment _MainDict;
  private DictSegment _StopWordDict;
  private DictSegment _QuantifierDict;
  private Configuration cfg;

  private Dictionary(Configuration cfg){
	  this.cfg = cfg;
	  loadMainDict();
	  loadStopWordDict();
	  loadQuantifierDict();
  }

  public static Dictionary initial(Configuration cfg)
  {
    if (singleton == null) {
      synchronized (Dictionary.class) {
        if (singleton == null) {
          singleton = new Dictionary(cfg);
          return singleton;
        }
      }
    }
    return singleton;
  }

  public static Dictionary getSingleton()
  {
    if (singleton == null) {
      throw new IllegalStateException("词典尚未初始化，请先调用initial方法");
    }
    return singleton;
  }

  public void addWords(Collection<String> words)
  {
    if (words != null)
      for (String word : words)
        if (word != null)
        {
          singleton._MainDict.fillSegment(word.trim().toLowerCase().toCharArray());
        }
  }

  public void disableWords(Collection<String> words)
  {
    if (words != null)
      for (String word : words)
        if (word != null)
        {
          singleton._MainDict.disableSegment(word.trim().toLowerCase().toCharArray());
        }
  }

  public Hit matchInMainDict(char[] charArray)
  {
    return singleton._MainDict.match(charArray);
  }

  public Hit matchInMainDict(char[] charArray, int begin, int length)
  {
    return singleton._MainDict.match(charArray, begin, length);
  }

  public Hit matchInQuantifierDict(char[] charArray, int begin, int length)
  {
    return singleton._QuantifierDict.match(charArray, begin, length);
  }

  public Hit matchWithHit(char[] charArray, int currentIndex, Hit matchedHit)
  {
    DictSegment ds = matchedHit.getMatchedDictSegment();
    return ds.match(charArray, currentIndex, 1, matchedHit);
  }

  public boolean isStopWord(char[] charArray, int begin, int length)
  {
    return singleton._StopWordDict.match(charArray, begin, length).isMatch();
  }

  private void loadMainDict()
  {
    this._MainDict = new DictSegment(Character.valueOf('\000'));

    InputStream is = getClass().getClassLoader().getResourceAsStream(this.cfg.getMainDictionary());
    if (is == null) {
      throw new RuntimeException("Main Dictionary not found!!!");
    }
    try
    {
      BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
      String theWord = null;
      do {
        theWord = br.readLine();
        if ((theWord != null) && (!"".equals(theWord.trim())))
          this._MainDict.fillSegment(theWord.trim().toLowerCase().toCharArray());
      }
      while (theWord != null);
    }
    catch (IOException ioe) {
      System.err.println("Main Dictionary loading exception.");
      ioe.printStackTrace();
      try
      {
        if (is != null) {
          is.close();
          is = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    finally
    {
      try
      {
        if (is != null) {
          is.close();
          is = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    loadExtDict(true);
  }

/*
  private void loadExtDict()
  {
    List<String> extDictFiles = this.cfg.getExtDictionarys();
    if (extDictFiles != null) {
      InputStream is = null;
      for (String extDictName : extDictFiles)
      {
        System.out.println("加载扩展词典：" + extDictName);
        is = getClass().getClassLoader().getResourceAsStream(extDictName);

        if (is != null)
        {
          try
          {
            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
            String theWord = null;
            do {
              theWord = br.readLine();
              if ((theWord != null) && (!"".equals(theWord.trim())))
              {
                this._MainDict.fillSegment(theWord.trim().toLowerCase().toCharArray());
              }
            }
            while (theWord != null);
          }
          catch (IOException ioe) {
            System.err.println("Extension Dictionary loading exception.");
            ioe.printStackTrace();
            try
            {
              if (is != null) {
                is.close();
                is = null;
              }
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
          finally
          {
            try
            {
              if (is != null) {
                is.close();
                is = null;
              }
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      }
    }
  }

*/

  /**
   * 从数据库 加载词库
   * @param isAsync 是否异步
   */
  private void loadExtDict(boolean isAsync) {
    int delay = isAsync ? 1000*10: 0; //异步默认延迟 10秒
    TimerUtil.newTimer("loadExtDict", new TimerTask() {
      @Override
      public void run() {
        int limit = 0, rows = 5000;
        List<String> extWordList = null;
        try {
          boolean next = true;
          int batchRows = 0;
          do{
            extWordList = DBUtil.findOneStrColumnList("SELECT `word` FROM solr_dic_ext_words LIMIT " + limit + ", " + rows);
            batchRows = extWordList.size();
            logger.info("加载扩展词典 " + batchRows + " 条");
            if(batchRows > 0){
              for (String extWord : extWordList) {
                singleton._MainDict.fillSegment(extWord.trim().toLowerCase().toCharArray());
              }
            }

            limit+= rows;
            if(batchRows != rows)
              next = false;
          } while(next);
          logger.info("加载扩展词典 完毕");
        } catch (SQLException e) {
          e.printStackTrace();
          logger.error("加载扩展词库失败", e);
        }
      }
    }, delay);
  }


  private void loadStopWordDict()
  {
    this._StopWordDict = new DictSegment(Character.valueOf('\000'));

    List<String> extStopWordDictFiles = this.cfg.getExtStopWordDictionarys();
    if (extStopWordDictFiles != null) {
      InputStream is = null;
      for (String extStopWordDictName : extStopWordDictFiles) {
        LogDeBugUtil.debug("加载扩展停止词典：" + extStopWordDictName);

        is = getClass().getClassLoader().getResourceAsStream(extStopWordDictName);

        if (is != null)
        {
          try
          {
            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
            String theWord = null;
            do {
              theWord = br.readLine();
              if ((theWord != null) && (!"".equals(theWord.trim())))
              {
                this._StopWordDict.fillSegment(theWord.trim().toLowerCase().toCharArray());
              }
            }
            while (theWord != null);
          }
          catch (IOException ioe) {
            System.err.println("Extension Stop word Dictionary loading exception.");
            ioe.printStackTrace();
            try
            {
              if (is != null) {
                is.close();
                is = null;
              }
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
          finally
          {
            try
            {
              if (is != null) {
                is.close();
                is = null;
              }
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      }
    }
  }

  private void loadQuantifierDict()
  {
    this._QuantifierDict = new DictSegment(Character.valueOf('\000'));

    InputStream is = getClass().getClassLoader().getResourceAsStream(this.cfg.getQuantifierDicionary());
    if (is == null)
      throw new RuntimeException("Quantifier Dictionary not found!!!");
    try
    {
      BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
      String theWord = null;
      do {
        theWord = br.readLine();
        if ((theWord != null) && (!"".equals(theWord.trim())))
          this._QuantifierDict.fillSegment(theWord.trim().toLowerCase().toCharArray());
      }
      while (theWord != null);
    }
    catch (IOException ioe) {
      System.err.println("Quantifier Dictionary loading exception.");
      ioe.printStackTrace();
      try
      {
        if (is != null) {
          is.close();
          is = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    finally
    {
      try
      {
        if (is != null) {
          is.close();
          is = null;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  
  /**
   * 重新 加载 扩展词典(含停止词)
   */
  public void reLoadExtDict() {
    logger.info("重新加载 扩展词典...");
    loadExtDict(false);
    logger.info("重新加载 扩展词典完毕...");
  }

  /**
   * 添加 扩展词到词库
   * @param extWordList
   */
  public Set<String> addExtDict(Collection<String> extWordList) {
    if(CollUtil.isEmpty(extWordList)){
      logger.warn("添加扩展词典失败，extWordList为空");
      return null;
    }
    Set<String> succList = new HashSet<>();
    char[] chars = null;
    Hit searchHit = new Hit();
    for (String extWord : extWordList) {
      chars = extWord.trim().toLowerCase().toCharArray();
      searchHit.setBegin(0);
      if(!singleton._MainDict.match(chars, 0, chars.length, searchHit).isMatch()){
        singleton._MainDict.fillSegment(chars);
        succList.add(extWord);
      }
    }
    logger.info("添加扩展词典 " + succList.size() + " 条");
    return succList;
  }

  /**
   * 添加 扩展词到词库
   * @param extWordList
   */
  public List<WordBean> addExtWordDict(Set<WordBean> extWordList) {
    if(CollUtil.isEmpty(extWordList)){
      logger.warn("添加扩展词典失败，extWordList为空");
      return null;
    }
    List<WordBean> succList = new ArrayList<>();
    char[] chars = null;
    Hit searchHit = new Hit();
    for (WordBean extWord : extWordList) {
      chars = extWord.getWord().trim().toLowerCase().toCharArray();
      searchHit.setBegin(0);
      if(!singleton._MainDict.match(chars, 0, chars.length, searchHit).isMatch()){
        singleton._MainDict.fillSegment(chars);
        succList.add(extWord);
      }
    }
    logger.info("添加扩展词典 " + succList.size() + " 条");
    return succList;
  }

}